package pl.wroc.uni.ii.pastuszka.algorithms.evolutionary.genetic;

import pl.wroc.uni.ii.pastuszka.algorithms.evolutionary.Individual;
import pl.wroc.uni.ii.pastuszka.algorithms.evolutionary.utils.BinaryRandom;

public class PBIL extends GeneticAlgorithmSchema {

  private float learningFactor;
  private float mutationProbability;
  private float mutationFactor;
  float[] probabilityVector;

  public void setLearningFactor(float learningFactor) {
    this.learningFactor = learningFactor;
  }

  public void setMutationProbability(float mutationProbability) {
    this.mutationProbability = mutationProbability;
  }

  public void setMutationFactor(float mutationFactor) {
    this.mutationFactor = mutationFactor;
  }

  public PBIL() {
  }

  public PBIL(int chromosomeLength, int populationSize,
      float learningFactor, float mutationProbability, float mutationFactor) {
    super(chromosomeLength, populationSize);
    setLearningFactor(learningFactor);
    setMutationFactor(mutationFactor);
    setMutationProbability(mutationProbability);
  }

  private void initializeProbabilityVector() {
    probabilityVector = new float[chromosomeLength];
    for (int i = 0; i < chromosomeLength; ++i) {
      probabilityVector[i] = 0.5f;
    }
  }

  private void learn() {
    Individual best = findBestIndividual();

    for (int i = 0; i < chromosomeLength; ++i) {
      probabilityVector[i] = (1 - learningFactor) * probabilityVector[i] +
          best.chromosome[i] * learningFactor;
    }

  }

  private void mutate() {
    for (int i = 0; i < chromosomeLength; ++i) {
      if (BinaryRandom.getBoolean(mutationProbability)) {
        probabilityVector[i] = (1 - mutationFactor) * probabilityVector[i] +
            BinaryRandom.getInt(0.5f) * mutationFactor;
      }
    }
  }

  @Override
  protected void applyGeneticOperators() {
    learn();
    mutate();
  }

  @Override
  protected void finishIteration() {
    createRandomPopulation(probabilityVector);
    super.finishIteration();
  }

  @Override
  protected void initializeAlgorithm() {
    initializeProbabilityVector();
    super.initializeAlgorithm();
  }

}
